/*
Definitions for Garmin USB protocol and implementation.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
int gusb_cmd_send(const garmin_usb_packet *obuf, size_t sz);
int gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz);
-int gusb_open(const char *portname);
-int gusb_close(const char *portname);
-int gusb_init(const char *portname);
+int gusb_init(const char *portname, gpsdevh **dh);
+int gusb_close(gpsdevh *);
/*
* New packet types in USB.
time_t Time; /* Unix time */
float alt; /* Altitude */
float dpth; /* Depth */
+ float temperature; /* Temperature. Degrees Celsius. */
+ int temperature_populated; /* True if above is valid. */
int32 heartrate; /* Heatrate as in Garmin 301 */
- int32 tnew; /* New track? */
- int32 ishdr; /* Track header? */
+ unsigned int tnew:1; /* New track? */
+ unsigned int ishdr:1; /* Track header? */
+ unsigned int no_latlon:1; /* True if no valid lat/lon found. */
int32 dspl; /* Display on map? */
int32 colour; /* Colour */
char trk_ident[256]; /* Track identifier */
char rte_link_subclass[18];
char rte_link_ident[256];
- char Time_populated; /* 1 if true */
- time_t Time; /* Unix time */
+ char time_populated; /* 1 if true */
+ time_t time; /* Unix time */
+ char temperature_populated;
+ float temperature; /* Degrees celsius. */
+ uint16 category;
+
} GPS_OWay, *GPS_PWay;
/*
-#include "gpsserial.h"
+#include "gpsdevice.h"
#include "gpssend.h"
#include "gpsread.h"
#include "gpsutil.h"
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
-** @modified 2004, 2005, 2006 Robert Lipe
+** @modified Copyright (C) 2004, 2005, 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
** Boston, MA 02111-1307, USA.
********************************************************************/
#include "gps.h"
-#include "garminusb.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>
+/*
+ * This violates the layering design, but is needed for device discovery.
+ * See the use of gps_is_usb and GPS_Packet_Read_usb below.
+ */
+#include "garminusb.h"
+#include "gpsusbint.h"
+
#define XMIN(a,b) (a < b? a : b)
static int32 GPS_A000(const char *port);
static void GPS_D154_Send(UC *data, GPS_PWay way, int32 *len);
static void GPS_D155_Send(UC *data, GPS_PWay way, int32 *len);
+static void GPS_D120_Get(int n, char *data);
+
static void GPS_D200_Get(GPS_PWay *way, UC *s);
static void GPS_D201_Get(GPS_PWay *way, UC *s);
static void GPS_D202_Get(GPS_PWay *way, UC *s);
static void GPS_D403_Send(UC *data, GPS_PWay way, int32 *len);
static void GPS_D450_Send(UC *data, GPS_PWay way, int32 *len);
-static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
-static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd);
+static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
+static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd);
static void GPS_D500_Send(UC *data, GPS_PAlmanac alm);
static void GPS_D501_Send(UC *data, GPS_PAlmanac alm);
static void GPS_D550_Send(UC *data, GPS_PAlmanac alm);
(void) GPS_Util_Little();
- /*
- * Decide here if the portname refers to a USB device and set the
- * global that's used as in inflection point for other decisions later.
- */
- gps_is_usb = (0 == strncmp(port, "usb:", 4));
-
ret = GPS_A000(port);
if(ret<0) return ret;
-
gps_save_time = GPS_Command_Get_Time(port);
- if(!gps_save_time) {
+
+ /*
+ * Some units may be unable to return time, such as a C320 when in
+ * charging mode. Only consider it fatal if the unit returns an error,
+ * not just absence of returning a time.
+ */
+ if(gps_save_time < 0) {
return FRAMING_ERROR;
}
************************************************************************/
static int32 GPS_A000(const char *port)
{
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int16 version;
int16 id;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
- if(!gps_is_usb && !GPS_Serial_Flush(fd))
+ if(!GPS_Device_Flush(fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_User("Unit:\t%s\nID:\t%d\nVersion:\t%.2f",
gps_save_string, gps_save_id, gps_save_version);
-
+#if 0
gps_date_time_transfer = pA600;
gps_date_time_type = pD600; /* All models so far */
gps_position_transfer = pA700;
gps_position_type = pD700; /* All models so far */
+#else
+ gps_date_time_transfer = -1;
+ gps_date_time_type = -1;
+ gps_position_transfer = -1;
+ gps_position_type = -1;
+#endif
gps_pvt_transfer = -1;
gps_pvt_type = -1;
gps_prx_waypt_transfer = -1;
gps_trk_hdr_type = -1;
gps_rte_link_type = -1;
- if(!GPS_Serial_Wait(fd))
+ if(!GPS_Device_Wait(fd))
{
GPS_Warning("A001 protocol not supported");
id = GPS_Protocol_Version_Change(id,version);
* reading until we incur a timeout.
* Worse still, the serial layer assumes a read timeout is a
* fatal error, while the USB layer (correctly) returns that error
- * to the caller. So we call GPS_Serial_Wait which spins into
+ * to the caller. So we call GPS_Device_Wait which spins into
* a delay/select for the serial system and a NOP for USB.
+ *
+ * Worse _yet_, this is the one place in all of Garmin Protocolsville
+ * where we don't know a priori how many packets will be sent in
+ * response. Since we want the lower levels of the USB handler
+ * to handle the ugliness of the "return to interrupt" packets, we
+ * reach behind that automation here and hand that ourselves.
*/
for (i = 0; i < 25; i++) {
rec->type = 0;
-
- if(!GPS_Serial_Wait(fd))
- goto carry_on;
- if (GPS_Packet_Read(fd, &rec) <= 0) {
- goto carry_on;
- }
+ if (gps_is_usb) {
+ GPS_Packet_Read_usb(fd, &rec, 0);
+ } else {
+ if(!GPS_Device_Wait(fd))
+ goto carry_on;
- GPS_Send_Ack(fd, &tra, &rec);
+ if (GPS_Packet_Read(fd, &rec) <= 0) {
+ goto carry_on;
+ }
+
+ GPS_Send_Ack(fd, &tra, &rec);
+ }
if (rec->type == 0xfd) {
- GPS_A001(rec);
-/* XXX This is wrong. Since we don't have a timeout on a read in Windows
- * (!) and this phase of the protocol is one of the very rare ones where we
- * don't know how many packets to expect, we have a big problem here.
- */
-goto carry_on;
+ GPS_A001(rec);
+ goto carry_on;
+ }
+
+ /*
+ * If a 296 has previously been interrupted, it's going to
+ * ignore the session request (grrrr) and continue to send
+ * us left over packets. So if we see anything that isn't
+ * part of our A000 discovery cycle, reset the counter and
+ * continue to loop.
+ *
+ * Garmin acknowledges this is a firmware defect.
+ */
+ if (rec->type < 0xf8) {
+ i = 0;
}
}
fatal("Failed to find a product inquiry response.\n");
if(gps_pvt_transfer != -1)
GPS_A800_Off(port,&fd);
-
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
case 'A':
GPS_User("\nCapability %c%d:", tag, data);
lasta = data;
- if(data<100)
- {
- if(data==10)
+ switch (data) {
+ case 10:
gps_device_command = pA010-10;
- else if(data==11)
- gps_device_command = pA011-10;
- else
- GPS_Protocol_Error(tag,data);
- continue;
- }
- else if(data<200)
- {
- if(data==100)
+ break;
+ case 11:
+ gps_device_command = pA010-10;
+ break;
+ case 100:
gps_waypt_transfer = pA100;
- /* Ignore A101 Waypoint Category Transfer Protocol. */
- continue;
- }
- else if(data<300)
- {
- if(data==200)
+ break;
+ case 101:
+ gps_category_transfer = pA101;
+ break;
+ case 200:
gps_route_transfer = pA200;
- else if(data==201)
+ break;
+ case 201:
gps_route_transfer = pA201;
- else
- GPS_Protocol_Error(tag,data);
- continue;
- }
- else if(data<400)
- {
- switch (data) {
- case 300:
- gps_trk_transfer = pA300;
- break;
- case 301:
- gps_trk_transfer = pA301;
- break;
- case 302:
- gps_trk_transfer = pA302;
- break;
- default:
- GPS_Protocol_Error(tag,data);
- }
- continue;
- }
- else if(data<500)
- {
- if(data!=400)
- GPS_Protocol_Error(tag,data);
- else
+ break;
+ case 300:
+ gps_trk_transfer = pA300;
+ break;
+ case 301:
+ gps_trk_transfer = pA301;
+ break;
+ case 302:
+ gps_trk_transfer = pA302;
+ break;
+ case 400:
gps_prx_waypt_transfer = pA400;
- continue;
- }
- else if(data<600)
- {
- if(data!=500)
- GPS_Protocol_Error(tag,data);
- else
+ break;
+ case 500:
gps_almanac_transfer = pA500;
- continue;
- }
- else if(data<700)
- {
- if (data == 600)
+ break;
+ case 600:
gps_date_time_transfer = pA600;
- else {
- /* Stupid undocumented 60C packets */
- /* GPS_Protocol_Error(tag,data); */
- continue;
- }
- continue;
- }
- else if(data<800)
- {
- if(data!=700)
- GPS_Protocol_Error(tag,data);
- gps_position_transfer = pA700;
- continue;
- }
- else if(data<900)
- {
- if (data == 800)
+ break;
+ case 700:
+ gps_position_transfer = pA700;
+ break;
+ case 800:
gps_pvt_transfer = pA800;
- /*
- * Undocumented A802 packets introduced on Vista 3.60 f/w.
- * else
- * GPS_Protocol_Error(tag,data);
- */
- continue;
- }
- else if (data < 1000)
- {
- /* Stupid Garmin undocumented "A900" packets
- * as returned by GPS76, Emap, III, and V in
- * later firmware.
- */
- continue;
- }
- else if (data < 1100)
- {
- /* Stupid Garmin undocumented "A100[2345]" packets
- * as returned by Forerunner 301.
- */
- continue;
- }
- else
- {
- GPS_Protocol_Error(tag,data);
+ break;
+
}
break;
GPS_User(" %c%d", tag, data);
if(lasta<200)
{
- if(data<=110 && data>=100)
- {
- gps_waypt_type = data;
- continue;
- }
- if(data<153 && data>=150)
- {
- gps_waypt_type = data;
- continue;
- }
- if(data<156 && data>=154)
- {
- gps_waypt_type = data;
- continue;
- }
- if (data == 120)
- {
- /* Quest 3.0 has a D120 for Wpt category ignore it*/
- continue;
+ switch (data) {
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ case 108:
+ case 109:
+ case 110:
+ /* 15x is panel-mount aviation */
+ case 150:
+ case 151:
+ case 152:
+ /* 153 not documented */
+ case 154:
+ case 155:
+ gps_waypt_type = data;
+ break;
+
+ /*
+ * Observered on Quest 3.0, 27xx, 27x, 29x.
+ */
+ case 120:
+ gps_category_type = data;
+ break;
+
+ case 200:
+ case 201:
+ case 202:
+ gps_rte_hdr_type = data;
+ break;
+
+ /* 210 Link packets appear in newer models, but the
+ * doc isn't sufficiently clear on what they really
+ * mean.
+ */
+ case 210:
+ gps_rte_link_type = data;
+ break;
+
}
- else
- GPS_Protocol_Error(tag,data);
}
case 301: gps_trk_type = pD301; break;
case 302: gps_trk_type = pD302; break;
case 303: gps_trk_type = pD303; break;
+ case 304: gps_trk_type = pD304; break;
case 310: gps_trk_hdr_type = pD310; break;
case 311: gps_trk_hdr_type = pD311; break;
case 312: gps_trk_hdr_type = pD312; break;
int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int, GPS_PWay *))
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
int32 i;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
if(!((*way)[i]=GPS_Way_New()))
return MEMORY_ERROR;
- if(!GPS_Packet_Read(fd, &rec))
+ if(!GPS_Packet_Read(fd, &rec)) {
return gps_errno;
- if(!GPS_Send_Ack(fd, &tra, &rec))
+ }
+
+ if(!GPS_Send_Ack(fd, &tra, &rec)) {
return gps_errno;
+ }
switch(gps_waypt_type)
{
if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
{
- GPS_Error("A100_GET: Error transferring waypoints. Expected %d completion code. Got %d", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type);
+ GPS_Error("A100_GET: Error transferring waypoints. Expected %d completion code. Got %d. %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n);
return FRAMING_ERROR;
}
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return n;
int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *))
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
int32 len;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
}
+/*
+ * Get the list of waypoint categories from the receiver.
+ */
+int32 GPS_A101_Get(const char *port)
+{
+ static UC data[2];
+ gpsdevh *fd;
+ GPS_PPacket tra;
+ GPS_PPacket rec;
+ int32 n;
+ int32 i;
+
+
+ if(!GPS_Device_On(port,&fd))
+ return gps_errno;
+
+ if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
+ return MEMORY_ERROR;
+
+ GPS_Util_Put_Short(data,
+ COMMAND_ID[gps_device_command].Cmnd_Transfer_Wpt_Cats);
+ GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data,
+ data,2);
+
+ if(!GPS_Write_Packet(fd,tra))
+ {
+ GPS_Error("A101_Get: Cannot write packet");
+ return FRAMING_ERROR;
+ }
+
+ if(!GPS_Get_Ack(fd, &tra, &rec))
+ {
+ GPS_Error("A101_Get: No acknowledge");
+ return FRAMING_ERROR;
+ }
+
+ GPS_Packet_Read(fd, &rec);
+ GPS_Send_Ack(fd, &tra, &rec);
+
+ n = GPS_Util_Get_Short(rec->data);
+ for (i = 0; i < n; ++i) {
+ if(!GPS_Packet_Read(fd, &rec)) {
+ return gps_errno;
+ }
+ if(!GPS_Send_Ack(fd, &tra, &rec)) {
+ return gps_errno;
+ }
+ switch(gps_category_type) {
+ case pD120:
+ GPS_D120_Get(i,(char *) rec->data);
+ break;
+ }
+ }
+ if(!GPS_Packet_Read(fd, &rec))
+ return gps_errno;
+ if(!GPS_Send_Ack(fd, &tra, &rec))
+ return gps_errno;
+
+ if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
+ {
+ GPS_Error("A101_Get: Error transferring waypoints. Expected %d completion code. Got %d. %d of %d received", LINK_ID[gps_link_type].Pid_Xfer_Cmplt, rec->type, i, n);
+ return FRAMING_ERROR;
+ }
+
+
+ if(!GPS_Device_Off(fd))
+ return gps_errno;
+
+ return 1;
+
+}
/* @funcstatic GPS_D100_Get *********************************************
**
p=s;
- (*way)->prot = 109;
+ (*way)->prot = protoid;
(*way)->wpt_class = *p++;
(*way)->colour = *p++;
(*way)->dspl = *p++;
p += 4; /* Skip over "outbound link ete in seconds */
if (protoid == 110) {
- p += 4; /* skip float temp */
- p += 4; /* skip longword time */
- p += 2; /* skip int "category membership " */
+ float gps_temp;
+ int gps_time;
+ gps_temp = GPS_Util_Get_Float(p);
+ p+=4;
+ if (gps_temp <= 1.0e24) {
+ (*way)->temperature_populated = 1;
+ (*way)->temperature = gps_temp;
+ }
+
+ gps_time = GPS_Util_Get_Uint(p);
+ p+=4;
+ /* The spec says that 0xffffffff is unknown, but the 60CSX with
+ * firmware 2.5.0 writes zero.
+ */
+ if (gps_time != 0xffffffff && gps_time != 0) {
+ (*way)->time_populated = 1;
+ (*way)->time = GPS_Math_Gtime_To_Utime(gps_time);
+ }
+ (*way)->category = GPS_Util_Get_Short(p);
+ p += 2;
}
q = (UC *) (*way)->ident;
return;
}
+/*
+ * We'll cheat for now. We know there are no more than 16 categories
+ * as of this writing for no data type exposes more than 16 bits in the
+ * bitmask of categories.
+ */
+static char categories[16][17];
+/*
+ * Read descriptor s into category number N;
+ */
+static
+void GPS_D120_Get(int cat_num, char *s)
+{
+ /* we're guaranteed to have no more than 16 chars plus a
+ * null terminator.
+ *
+ * If the unit returned no string, the user has not configured one,
+ * so mimic the behaviour of the 276/296.
+ */
+
+ if (*s) {
+ strncpy(categories[cat_num], s, sizeof (categories[0]));
+ } else {
+ snprintf(categories[cat_num], sizeof (categories[0]),
+ "Category %d", cat_num+1);
+ }
+}
/* @funcstatic GPS_D100_Send *******************************************
GPS_Util_Put_Float(p, temp);
p += 4;
- if (way->Time_populated) {
- GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->Time));
+ if (way->time_populated) {
+ GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(way->time));
p+=sizeof(uint32);
} else {
for(i=0;i<4;++i) *p++ = 0xff; /* unknown time*/
}
- for(i=0;i<2;++i) *p++ = 0x00; /* D110 category */
+ GPS_Util_Put_Short(p, (US) way->category);; /* D110 category */
+ p += 2;
}
q = (UC *) way->ident;
int32 GPS_A200_Get(const char *port, GPS_PWay **way)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
int32 i;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return n;
int32 GPS_A201_Get(const char *port, GPS_PWay **way)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
int32 i;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return n;
int32 GPS_A200_Send(const char *port, GPS_PWay *way, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
int32 len;
UC method;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
int32 len;
UC method;
- if(!GPS_Serial_On(port,&fd))
+ if(!GPS_Device_On(port,&fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
int32 GPS_A300_Get(const char *port, GPS_PTrack **trk)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
return GPS_UNSUPPORTED;
}
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
for(i=0;i<n;++i)
if(!((*trk)[i]=GPS_Track_New()))
return MEMORY_ERROR;
-
switch(gps_trk_type)
{
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return ret;
int32 GPS_A301_Get(const char *port, GPS_PTrack **trk)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
return GPS_UNSUPPORTED;
}
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
if(!((*trk)[i]=GPS_Track_New()))
return MEMORY_ERROR;
-
for(i=0;i<n;++i)
{
if(!GPS_Packet_Read(fd, &rec))
return gps_errno;
if(!GPS_Send_Ack(fd, &tra, &rec))
return gps_errno;
-
if(rec->type == LINK_ID[gps_link_type].Pid_Trk_Hdr)
{
switch(gps_trk_hdr_type)
GPS_D302b_Get(&((*trk)[i]),rec->data);
break;
case pD303:
+ case pD304:
GPS_D303b_Get(&((*trk)[i]),rec->data);
break;
default:
return gps_errno;
if(!GPS_Send_Ack(fd, &tra, &rec))
return gps_errno;
-
if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
{
GPS_Error("A301_Get: Error transferring tracks");
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return n;
int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
return GPS_UNSUPPORTED;
}
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
return GPS_UNSUPPORTED;
}
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
**
** @return [int32] number of entries read
************************************************************************/
-int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd)
+int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *fd)
{
GPS_PPacket tra;
GPS_PPacket rec;
{
UC *p;
uint32 t;
- double temp;
+ double gps_temp;
p=data;
/* The only difference between 302 and 301 is the presence of temp
* in the middle. Nice planning, eh?
*/
- temp = GPS_Util_Get_Float(p);
+ gps_temp = GPS_Util_Get_Float(p);
+ if (gps_temp <= 1.0e24) {
+ (*trk)->temperature_populated = 1;
+ (*trk)->temperature = gps_temp;
+ }
+
p+=sizeof(float);
(*trk)->tnew = *p;
uint32 t;
uint32 raw_lat, raw_lon;
int lat_undefined, lon_undefined;
-
+int i;
p=data;
/* Latitude and longitude are sometimes invalid (0x7fffffff or
(*trk)->lon = GPS_Math_Semi_To_Deg(raw_lon);
p+=sizeof(int32);
+ /*
+ * Let the caller decide if it wants to toss trackpionts with only
+ * hear and/or time data.
+ */
+ if (lat_undefined || lon_undefined) {
+ (*trk)->no_latlon = 1;
+ }
+
if (lat_undefined != lon_undefined)
GPS_Warning("GPS_D303b_Get: assumption (lat_undefined == lon_undefined) violated");
t = GPS_Util_Get_Uint(p);
+
if(!t || t==0x7fffffff || t==0xffffffff)
(*trk)->Time=0;
else
p+=sizeof(float);
/* Heartrate is reported as 0 if there is no signal from
- * a heartrate monitor. A uint32 is a bit overkill, even
- * for me in my state of fitness. Perhaps this is actually
- * a char or uint16, leaving room for a trk_seg bool at the end?
+ * a heartrate monitor.
+ * 305 and 304 are identical until now.
*/
- (*trk)->heartrate = GPS_Util_Get_Uint(p);
- p+=sizeof(uint32);
+ switch (gps_trk_type) {
+ case pD304:
+ p+=4; /* A float indicating number of meters travelled. */
+ (*trk)->heartrate = (*p++);
+ /* crank cadence, RPM, 0xff if invalid. */
+ p++;
+ /* sensor present. Boolean */
+ p++;
+
+ break;
+ case pD303:
+ (*trk)->heartrate = *p++;
+ break;
+ }
/* There doesn't seem to be a trk_seg bool, or at least I've not
* observed it yet. One possibility is to start a new segment
/* Forerunner */
identifier = GPS_Util_Get_Short(s);
sprintf((*trk)->trk_ident, "%d", identifier);
+ (*trk)->tnew = 1;
return;
}
int32 GPS_A400_Get(const char *port, GPS_PWay **way)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
return GPS_UNSUPPORTED;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
if(!GPS_Get_Ack(fd, &tra, &rec))
return gps_errno;
- if(!GPS_Serial_Chars_Ready(fd))
+ if(!GPS_Device_Chars_Ready(fd))
{
GPS_Warning("A400 (ppx) protocol not supported");
GPS_Packet_Del(&rec);
GPS_Packet_Del(&tra);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return GPS_UNSUPPORTED;
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return n;
int32 GPS_A400_Send(const char *port, GPS_PWay *way, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
if(gps_prx_waypt_transfer == -1)
return GPS_UNSUPPORTED;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
int32 GPS_A500_Get(const char *port, GPS_PAlmanac **alm)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 n;
int32 i;
int32 ret;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return ret;
int32 GPS_A500_Send(const char *port, GPS_PAlmanac *alm, int32 n)
{
UC data[GPS_ARB_LEN];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 i;
int32 posnsent;
int32 ret;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
* the time. Note that the time sent is held in gps_save_time
* global
*/
- if(GPS_Serial_Wait(fd))
+ if(GPS_Device_Wait(fd))
{
if(!GPS_Packet_Read(fd, &rec))
return gps_errno;
* the position. Note that the posn sent is held in gps_save_lat
* and gps_save_lon global!
*/
- if(GPS_Serial_Wait(fd))
+ if(GPS_Device_Wait(fd))
{
if(!GPS_Packet_Read(fd, &rec))
return gps_errno;
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
**
** @return [int32] number of entries read
************************************************************************/
-static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D500_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
{
GPS_PPacket tra;
GPS_PPacket rec;
**
** @return [int32] number of entries read
************************************************************************/
-static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D501_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
{
GPS_PPacket tra;
GPS_PPacket rec;
**
** @return [int32] number of entries read
************************************************************************/
-static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D550_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
{
GPS_PPacket tra;
GPS_PPacket rec;
**
** @return [int32] number of entries read
************************************************************************/
-static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, int32 fd)
+static int32 GPS_D551_Get(GPS_PAlmanac *alm, int32 entries, gpsdevh *fd)
{
GPS_PPacket tra;
GPS_PPacket rec;
time_t GPS_A600_Get(const char *port)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
time_t ret;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return ret;
************************************************************************/
int32 GPS_A600_Send(const char *port, time_t Time)
{
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
int32 posnsent=0;
int32 ret=0;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
* the position. Note that the posn sent is held in gps_save_lat
* and gps_save_lon globals!
*/
- if(GPS_Serial_Wait(fd))
+ if(GPS_Device_Wait(fd))
{
if(!GPS_Packet_Read(fd, &rec))
return gps_errno;
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
int32 GPS_A700_Get(const char *port, double *lat, double *lon)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
************************************************************************/
int32 GPS_A700_Send(const char *port, double lat, double lon)
{
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
**
** @return [int32] success
************************************************************************/
-int32 GPS_A800_On(const char *port, int32 *fd)
+int32 GPS_A800_On(const char *port, gpsdevh **fd)
{
static UC data[2];
GPS_PPacket tra;
GPS_PPacket rec;
- if(!GPS_Serial_On(port, fd))
+ if(!GPS_Device_On(port, fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
**
** @return [int32] success
************************************************************************/
-int32 GPS_A800_Off(const char *port, int32 *fd)
+int32 GPS_A800_Off(const char *port, gpsdevh **fd)
{
static UC data[2];
GPS_PPacket tra;
GPS_Packet_Del(&rec);
GPS_Packet_Del(&tra);
- if(!GPS_Serial_Off(port, *fd))
- return gps_errno;
+// if(!GPS_Device_Off(*fd))
+// return gps_errno;
return 1;
}
**
** @return [int32] success
************************************************************************/
-int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet)
+int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet)
{
GPS_PPacket tra;
GPS_PPacket rec;
int32 GPS_A906_Get(const char *port, GPS_OLap_Data **lap)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket lappkt;
GPS_PPacket recpkt;
int32 i, n;
if (gps_lap_transfer == -1)
return GPS_UNSUPPORTED;
- if (!GPS_Serial_On(port, &fd))
+ if (!GPS_Device_On(port, &fd))
return gps_errno;
if (!(lappkt = GPS_Packet_New() ) || !(recpkt = GPS_Packet_New()))
GPS_Packet_Del(&lap);
GPS_Packet_Del(&rec);
- if (!GPS_Serial_Off(port, fd))
+ if (!GPS_Device_Off(fd))
return gps_errno;
return ret;
case 50: *xinfo = "Xfer PVT Stop"; break;
case 92: *xinfo = "Flight Records"; break;
case 117: *xinfo = "Xfer Laps"; break;
+ case 121: *xinfo = "Xfer Categories"; break;
default: *xinfo = "Unknown";
}
return "CMDDAT";
return "SESREQ";
if (p == GUSB_SESSION_ACK)
return "SESACK";
+ if (p == 152)
+ return "WPTCAT";
return "UNKNOWN";
}
int32 GPS_Init(const char *port);
int32 GPS_A100_Get(const char *port, GPS_PWay **way, int (*cb)(int ct, GPS_PWay *));
+int32 GPS_A101_Get(const char *port);
int32 GPS_A100_Send(const char *port, GPS_PWay *way, int32 n, int (*cb)(GPS_PWay *));
int32 GPS_A200_Get(const char *port, GPS_PWay **way);
int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n);
int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n);
-int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, int32 fd);
+int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *h);
void GPS_D300b_Get(GPS_PTrack *trk, UC *data);
void GPS_D301b_Get(GPS_PTrack *trk, UC *data);
void GPS_D302b_Get(GPS_PTrack *trk, UC *data);
void GPS_D700_Get(GPS_PPacket packet, double *lat, double *lon);
void GPS_D700_Send(GPS_PPacket *packet, double lat, double lon);
-int32 GPS_A800_On(const char *port, int32 *fd);
-int32 GPS_A800_Off(const char *port, int32 *fd);
-int32 GPS_A800_Get(int32 *fd, GPS_PPvt_Data *packet);
+int32 GPS_A800_On(const char *port, gpsdevh **fd);
+int32 GPS_A800_Off(const char *port, gpsdevh **fd);
+int32 GPS_A800_Get(gpsdevh **fd, GPS_PPvt_Data *packet);
void GPS_D800_Get(GPS_PPacket packet, GPS_PPvt_Data *pvt);
const char * Get_Pkt_Type(unsigned char p, unsigned char d0, const char **xinfo);
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2005, 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
int32 GPS_Command_Off(const char *port)
{
static UC data[2];
- int32 fd;
+ gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
GPS_Util_Little();
- gps_is_usb = (0 == strncmp(port, "usb:", 4));
-
- if(!GPS_Serial_On(port, &fd))
+ if(!GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
if(!GPS_Write_Packet(fd,tra))
return gps_errno;
- if(!GPS_Serial_Chars_Ready(fd))
+ if(!GPS_Device_Chars_Ready(fd))
{
if(!GPS_Get_Ack(fd, &tra, &rec))
return gps_errno;
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Serial_Off(port, fd))
+ if(!GPS_Device_Off(fd))
return gps_errno;
return 1;
{
int32 ret=0;
+ /*
+ * It's a bit tacky to do this up front without ticking the
+ * progress meter, but this come in pretty quickly...
+ */
+ if (gps_category_transfer) {
+ ret = GPS_A101_Get(port);
+ if (!ret) {
+fatal("blah");
+ return PROTOCOL_ERROR;
+ }
+
+ }
+
switch(gps_waypt_transfer)
{
case pA100:
ret = GPS_A301_Get(port,trk);
break;
default:
- GPS_Error("Get_Track: Unknown track protocol\n");
+ GPS_Error("Get_Track: Unknown track protocol %d\n", gps_trk_transfer);
return PROTOCOL_ERROR;
}
case pA600:
ret = GPS_A600_Get(port);
break;
+ /*
+ * If the unit doesn't support it (i.e. a C320 in charging mode),
+ * but don't treat as error; return as zero.
+ */
+ case -1:
+ return 0;
default:
GPS_Error("Get_Time: Unknown date/time protocol");
return PROTOCOL_ERROR;
case pA700:
ret = GPS_A700_Get(port,lat,lon);
break;
+ /*
+ * If the unit doesn't support it (i.e. a C320 in charging mode),
+ * zero lat/lon, but don't treat as error.
+ */
+ case -1:
+ *lat = *lon = 0.0;
+ break;
default:
GPS_Error("Get_Position: Unknown position protocol");
return PROTOCOL_ERROR;
** @return [int32] success if supported and GPS starts sending
************************************************************************/
-int32 GPS_Command_Pvt_On(const char *port, int32 *fd)
+int32 GPS_Command_Pvt_On(const char *port, gpsdevh **fd)
{
int32 ret=0;
** @return [int32] success
************************************************************************/
-int32 GPS_Command_Pvt_Off(const char *port, int32 *fd)
+int32 GPS_Command_Pvt_Off(const char *port, gpsdevh **fd)
{
int32 ret=0;
** @return [int32] success
************************************************************************/
-int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt)
+int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt)
{
int32 ret=0;
int32 GPS_Command_Get_Position(const char *port, double *lat, double *lon);
int32 GPS_Command_Send_Position(const char *port, double lat, double lon);
-int32 GPS_Command_Pvt_On(const char *port, int32 *fd);
-int32 GPS_Command_Pvt_Off(const char *port, int32 *fd);
-int32 GPS_Command_Pvt_Get(int32 *fd, GPS_PPvt_Data *pvt);
+int32 GPS_Command_Pvt_On(const char *port, gpsdevh **fd);
+int32 GPS_Command_Pvt_Off(const char *port, gpsdevh **fd);
+int32 GPS_Command_Pvt_Get(gpsdevh **fd, GPS_PPvt_Data *pvt);
int32 GPS_Command_Get_Almanac(const char *port, GPS_PAlmanac **alm);
int32 GPS_Command_Send_Almanac(const char *port, GPS_PAlmanac *alm, int32 n);
--- /dev/null
+/*
+ Abstraction of underlying device types, serial or USB. OS agnostic..
+
+ Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+ This program is free software{} you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation{} either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY{} without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program{} if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gps.h"
+#include "gpsdevice.h"
+#include "gpsserial.h"
+
+extern gps_device_ops gps_serial_ops;
+extern gps_device_ops gps_usb_ops;
+gps_device_ops *ops = NULL;
+
+int32 GPS_Device_On(const char *port, gpsdevh **fd)
+{
+ gps_is_usb = (0 == case_ignore_strncmp(port, "usb:", 4));
+
+ if (gps_is_usb) {
+ ops = &gps_usb_ops;
+ } else {
+ ops = &gps_serial_ops;
+ }
+
+ return (ops->Device_On)(port, fd);
+}
+
+int32 GPS_Device_Off(gpsdevh * fd)
+{
+ return (ops->Device_Off)(fd);
+}
+
+int32 GPS_Device_Wait(gpsdevh * fd)
+{
+ return (ops->Device_Wait)(fd);
+}
+
+int32 GPS_Device_Chars_Ready(gpsdevh * fd)
+{
+ return (ops->Device_Chars_Ready)(fd);
+}
+
+int32 GPS_Device_Flush(gpsdevh * fd)
+{
+ return (ops->Device_Flush)(fd);
+}
+
+int32 GPS_Write_Packet(gpsdevh * fd, GPS_PPacket packet)
+{
+ return (ops->Write_Packet)(fd, packet);
+}
+
+int32 GPS_Packet_Read(gpsdevh * fd, GPS_PPacket *packet)
+{
+ return (ops->Read_Packet)(fd, packet);
+}
+
+int32 GPS_Send_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec)
+{
+ return (ops->Send_Ack)(fd, tra, rec);
+}
+
+int32 GPS_Get_Ack(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec)
+{
+ return (ops->Get_Ack)(fd, tra, rec);
+}
+
+void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
+{
+ (ops->Make_Packet)(packet, type, data, n);
+}
--- /dev/null
+/*
+ Abstraction of underlying device types.
+
+ Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef gpsdevice_h
+#define gpsdevice_h
+
+typedef struct gpsdevh gpsdevh;
+
+#include "gps.h"
+
+#define usecDELAY 180000 /* Microseconds before GPS sends A001 */
+
+
+int32 GPS_Device_Chars_Ready(gpsdevh *fd);
+int32 GPS_Device_On(const char *port, gpsdevh **fd);
+int32 GPS_Device_Off(gpsdevh *fd);
+int32 GPS_Device_Wait(gpsdevh * fd);
+int32 GPS_Device_Flush(gpsdevh * fd);
+int32 GPS_Device_Read(int32 ignored, void *ibuf, int size);
+int32 GPS_Device_Write(int32 ignored, const void *obuf, int size);
+void GPS_Device_Error(char *hdr, ...);
+int32 GPS_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32 GPS_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+int32 GPS_Packet_Read(gpsdevh *fd, GPS_PPacket *packet);
+int32 GPS_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+
+typedef int32 (*gps_device_op)(gpsdevh *);
+typedef int32 (*gps_device_op5)(const char *, gpsdevh **fd);
+typedef int32 (*gps_device_op10)(gpsdevh * fd, GPS_PPacket *tra, GPS_PPacket *rec);
+typedef int32 (*gps_device_op12)(gpsdevh * fd, GPS_PPacket packet);
+typedef int32 (*gps_device_op13)(gpsdevh * fd, GPS_PPacket *packet);
+typedef void (*gps_device_op14)(GPS_PPacket *packet, UC type, UC *data, int16 n);
+typedef struct {
+ gps_device_op5 Device_On;
+ gps_device_op Device_Off;
+ gps_device_op Device_Chars_Ready;
+ gps_device_op Device_Wait;
+ gps_device_op Device_Flush;
+ gps_device_op10 Send_Ack;
+ gps_device_op10 Get_Ack;
+ gps_device_op13 Read_Packet;
+ gps_device_op14 Make_Packet;
+ gps_device_op12 Write_Packet;
+} gps_device_ops;
+
+#endif /* gpsdevice.h */
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*
+ Serial operations.
+
+ Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gpsdevice.h"
+#include "gpsserial.h"
+#include "gpsread.h"
+
+gps_device_ops gps_serial_ops = {
+ GPS_Serial_On,
+ GPS_Serial_Off,
+ GPS_Serial_Chars_Ready,
+ GPS_Serial_Wait,
+ GPS_Serial_Flush,
+ GPS_Serial_Send_Ack,
+ GPS_Serial_Get_Ack,
+ GPS_Serial_Packet_Read,
+ GPS_Serial_Make_Packet,
+ GPS_Serial_Write_Packet,
+};
--- /dev/null
+/*
+ USB operations.
+
+ Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "gpsdevice.h"
+#include "garminusb.h"
+#include "gpsusbint.h"
+#include "gpsusbcommon.h"
+
+static int32 success_stub(void)
+{
+ return 1;
+}
+
+static int32 gdu_on(const char *port, gpsdevh **fd)
+{
+ return gusb_init(port, fd);
+}
+
+static int32 gdu_off(gpsdevh *dh)
+{
+ return gusb_close(dh);
+}
+
+static int32 gdu_read(gpsdevh *fd, GPS_PPacket *packet)
+{
+ /* Default is to eat bulk request packets. */
+ return GPS_Packet_Read_usb(fd, packet, 1);
+}
+
+gps_device_ops gps_usb_ops = {
+ gdu_on,
+ gdu_off,
+ (gps_device_op) success_stub,
+ (gps_device_op) success_stub,
+ (gps_device_op) success_stub,
+ (gps_device_op10) success_stub,
+ (gps_device_op10) success_stub,
+ gdu_read,
+ GPS_Make_Packet_usb,
+ GPS_Write_Packet_usb
+};
/*
Physical/OS USB layer to talk to libusb.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#if HAVE_LIBUSB
#include <usb.h>
#include "gps.h"
+#include "gpslibusb.h"
#include "garminusb.h"
+#include "gpsusbcommon.h"
#define GARMIN_VID 0x91e
* coalescion into packets anyway becuase of their serial background) will
* compensate.
*/
-#define TMOUT_I 0100 /* Milliseconds to timeout intr pipe access. */
+#define TMOUT_I 3000 /* Milliseconds to timeout intr pipe access. */
+#define TMOUT_B 3000 /* Milliseconds to timeout bulk pipe access. */
-int gusb_intr_in_ep;
-int gusb_bulk_out_ep;
-int gusb_bulk_in_ep;
-static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0};
-garmin_usb_packet iresp;
-
-static struct usb_bus *busses;
-static usb_dev_handle *udev;
-static void garmin_usb_scan(void);
-static void garmin_usb_syncup(void);
-
-int
-gusb_init(const char *portname)
-{
-// usb_set_debug(99);
- usb_init();
- usb_find_busses();
- usb_find_devices();
- busses = usb_get_busses();
- garmin_usb_scan();
-
- return 1;
-}
+/*
+ * TODO: this should all be moved into libusbdata in gpslibusb.h,
+ * allocated once here in gusb_start, and deallocated at the end.
+ */
+static int gusb_intr_in_ep;
+static int gusb_bulk_out_ep;
+static int gusb_bulk_in_ep;
-static void dump(char *msg, const unsigned char *in, int r)
-{
- int i;
- printf("%s: %d\n", msg, r);
- for (i = 0; i < r; i++) {
- printf ("%02x ", in[i]);
- }
- if (r) printf("\n");
- for (i = 0; i < r; i++) {
- printf ("%c", isalnum(in[i]) ? in[i] : '.');
- }
- if (r) printf("\n");
-}
+// static struct usb_bus *busses;
+static usb_dev_handle *udev;
+static void garmin_usb_scan(libusb_unit_data *, int);
-int
-gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
+static int
+gusb_libusb_send(const garmin_usb_packet *opkt, size_t sz)
{
int r;
+
+ r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_B);
- r = usb_bulk_write(udev, gusb_bulk_out_ep, (char *)(void *)opkt->dbuf, sz, TMOUT_I);
- if (gps_show_bytes) {
- dump ("Sent", &opkt->dbuf[0], r);
- }
- if (r != sz) {
+ if (r != (int) sz) {
fprintf(stderr, "Bad cmdsend r %d sz %d\n", r, sz);
if (r < 0) {
fatal("usb_bulk_write failed. '%s'\n",
return r;
}
-int
-gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
+static int
+gusb_libusb_get(garmin_usb_packet *ibuf, size_t sz)
{
unsigned char *buf = &ibuf->dbuf[0];
- unsigned char *obuf = buf;
- int r = -1, tsz = 0;
+ int r = -1;
r = usb_interrupt_read(udev, gusb_intr_in_ep, (char *) buf, sz, TMOUT_I);
+ return r;
+}
- tsz = r;
-
- if (gps_show_bytes) {
- int i;
- const char *m1, *m2;
- printf("RX [%d]:", tsz);
- for(i=0;i<tsz;i++)
- GPS_Diag("%02x ", obuf[i]);
- for(i=0;i<tsz;i++)
- GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
+static int
+gusb_libusb_get_bulk(garmin_usb_packet *ibuf, size_t sz)
+{
+ int r;
+ unsigned char *buf = &ibuf->dbuf[0];
- m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2);
- GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
- printf("\n");
- }
+ r = usb_bulk_read(udev, gusb_bulk_in_ep, (char *) buf, sz, TMOUT_B);
- return (r);
+ return r;
}
-void
-garmin_usb_teardown(void)
+
+static int
+gusb_teardown(const char *pname)
{
if (udev) {
usb_release_interface(udev, 0);
usb_close(udev);
udev = NULL;
}
+ return 0;
}
void
int i;
if (udev) return;
-
/*
- * Linux _requires_ the reset. OSX doesn't work if we DO reset it.
- * I really should study this more, but for now, we'll just avoid the
- * reset on Apple's OSX.
+ * Linux _requires_ the reset. OSX doesn't work if we
+ * DO reset it. I really should study this more, but for
+ * now, we'll just avoid the reset on Apple's OSX.
*/
#if !defined (__APPLE__)
udev = usb_open(dev);
#endif /* APPLE */
udev = usb_open(dev);
- atexit(garmin_usb_teardown);
+ atexit((void(*)())gusb_teardown);
+
if (!udev) { fatal("usb_open failed\n"); }
/*
* Hrmph. No iManufacturer or iProduct headers....
*/
if (usb_set_configuration(udev, 1) < 0) {
- fatal("usb_set_configuration failed\n");
+ fatal("usb_set_configuration failed: %s\n", usb_strerror());
}
if (usb_claim_interface(udev, 0) < 0) {
-// abort();
+ fatal("Claim interfaced failed: %s\n", usb_strerror());
}
-
for (i = 0; i < dev->config->interface->altsetting->bNumEndpoints; i++) {
struct usb_endpoint_descriptor * ep;
ep = &dev->config->interface->altsetting->endpoint[i];
* that loop without non-zero values for all three, we're hosed.
*/
if (gusb_intr_in_ep && gusb_bulk_in_ep && gusb_bulk_out_ep) {
- garmin_usb_syncup();
- } else {
- fatal("Could not identify endpoints on USB device.\nFound endpoints Intr In %d Bulk Out %d Bulk In %d\n", gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep);
+ gusb_syncup();
+ return;
}
- return;
-}
-
-void
-garmin_usb_syncup(void)
-{
- int maxct = 5;
- int maxtries;
-
- for (maxtries = maxct; maxtries; maxtries--) {
-
- le_write16(&iresp.gusb_pkt.pkt_id, 0);
- le_write32(&iresp.gusb_pkt.datasz, 0);
- le_write32(&iresp.gusb_pkt.databuf, 0);
-
- gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
- gusb_cmd_get(&iresp, sizeof(iresp));
-
- if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) &&
- (le_read32(iresp.gusb_pkt.datasz) == 4)) {
- if (gps_show_bytes) {
- fprintf(stderr, "Synced in %d\n", maxct - maxtries);
- }
-// fprintf(stderr, "Unit number %u\n", iresp[15] << 24 | iresp[14] << 16 | iresp[13] << 8 | iresp[12]);
- return;
- }
- }
-return;
- fatal("Cannot sync up with receiver\n");
+ fatal("Could not identify endpoints on USB device.\n"
+ "Found endpoints Intr In 0x%x Bulk Out 0x%x Bulk In %0xx\n",
+ gusb_intr_in_ep, gusb_bulk_out_ep, gusb_bulk_in_ep);
}
static
-void garmin_usb_scan(void)
+void garmin_usb_scan(libusb_unit_data *lud, int req_unit_number)
{
- int initted = 0;
+ int found_devices = 0;
struct usb_bus *bus;
- for (bus = busses; bus; bus = bus->next) {
+ for (bus = lud->busses; bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
* we just take the easy way out for now.
*/
if (dev->descriptor.idVendor == GARMIN_VID) {
- garmin_usb_start(dev);
- initted++;
+ /* Nuvi */
+ if (dev->descriptor.idProduct == 0x19)
+ continue;
+ if (req_unit_number < 0) {
+ garmin_usb_start(dev);
+ gusb_teardown(NULL);
+ } else
+ if (req_unit_number == found_devices)
+ garmin_usb_start(dev);
+ found_devices++;
}
}
}
- if (0 == initted) {
+ if (req_unit_number < 0) {
+ gusb_list_units();
+ exit (0);
+ }
+ if (0 == found_devices) {
fatal("Found no Garmin USB devices.\n");
}
}
+
+static gusb_llops_t libusb_llops = {
+ gusb_libusb_get,
+ gusb_libusb_get_bulk,
+ gusb_libusb_send,
+ gusb_teardown
+};
+
+int
+gusb_init(const char *portname, gpsdevh **dh)
+{
+ int req_unit_number = 0;
+ libusb_unit_data *lud = xcalloc(sizeof (libusb_unit_data), 1);
+ *dh = (gpsdevh*) lud;
+
+// usb_set_debug(99);
+ usb_init();
+ gusb_register_ll(&libusb_llops);
+
+ /* if "usb:N", read "N" to be the unit number. */
+ if (strlen(portname) > 4) {
+ req_unit_number = atoi(portname + 4);
+ }
+
+ usb_find_busses();
+ usb_find_devices();
+ lud->busses = usb_get_busses();
+ garmin_usb_scan(lud, req_unit_number);
+
+ return 1;
+}
+
#endif /* HAVE_LIBUSB */
** @version 1.0
** @modified December 28th 1999 Alan Bleasby. First version
** @modified June 29th 2000 Alan Bleasby. NMEA additions
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
** Boston, MA 02111-1307, USA.
********************************************************************/
#include "gps.h"
-#include "garminusb.h"
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
}
-
/* @func GPS_Packet_Del ***********************************************
**
** Packet destructor
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
struct COMMANDDATA COMMAND_ID[2]=
{
{
- 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x31,0x32,92,117,121
}
,
{
UC Pid_Protocol_Array;
UC Pid_Product_Rqst;
UC Pid_Product_Data;
+ UC Pid_Wpt_Cat_Data;
}
;
UC Cmnd_Turn_Off_Pwr;
UC Cmnd_Start_Pvt_Data;
UC Cmnd_Stop_Pvt_Data;
+ UC Cmnd_FlightBook_Transfer;
UC Cmnd_Transfer_Lap;
+ UC Cmnd_Transfer_Wpt_Cats;
}
;
#define pA100 100
int32 gps_waypt_transfer;
+/*
+ * Waypoint category transfer protocol
+ */
+#define pA101 101
+int32 gps_category_transfer;
/*
* Route Transfer Protocol
#define pA300 300
#define pA301 301
#define pA302 302
+#define pA304 304
int32 gps_trk_transfer;
/*
int32 gps_rte_type;
int32 gps_waypt_type;
+/*
+ * Waypoint category types
+ */
+#define pD120 120
+int32 gps_category_type;
/*
* Rte Header Type
#define pD301 301
#define pD302 302
#define pD303 303
+#define pD304 304
int32 gps_trk_type;
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
** Boston, MA 02111-1307, USA.
********************************************************************/
#include "gps.h"
-#include "gpsusbint.h"
+#include "gpsserial.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
-/* @func GPS_Packet_Read ***********************************************
+/* @func GPS_Serial_Packet_Read ***********************************************
**
** Read a packet
**
** @return [int32] number of bytes read
**********************************************************************/
-int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet)
+int32 GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet)
{
time_t start;
int32 n;
isDLE = gpsFalse;
p = (*packet)->data;
- if (gps_is_usb) {
- return GPS_Packet_Read_usb(fd, packet);
- }
-
start = GPS_Time_Now();
GPS_Diag("Rx Data:");
while(GPS_Time_Now() < start+GPS_TIME_OUT)
(*packet)->dle = u;
if(u != DLE)
{
- (void) fprintf(stderr,"GPS_Packet_Read: No DLE\n");
+ (void) fprintf(stderr,"GPS_Packet_Read: No DLE. Data received, but probably not a garmin packet.\n");
(void) fflush(stderr);
return 0;
}
}
m1 = Get_Pkt_Type((*packet)->type, (*packet)->data[0], &m2);
+ if (gps_show_bytes) {
+ GPS_Diag(" ");
+ for (i = 0; i < (*packet)->n; i++) {
+ char c = (*packet)->data[i];
+ GPS_Diag("%c", isalnum(c) ? c : '.');
+ }
+ GPS_Diag(" ");
+ }
GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
return (*packet)->n;
}
}
- GPS_Error("GPS_Packet_Read: Time-out");
+ GPS_Error("GPS_Packet_Read: Timeout. No data received.");
gps_errno = SERIAL_ERROR;
return 0;
** @return [int32] true if ACK
**********************************************************************/
-int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec)
+int32 GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec)
{
- if (gps_is_usb) {
- return 1;
- }
-
- if(!GPS_Packet_Read(fd, rec))
+ if(!GPS_Serial_Packet_Read(fd, rec))
return 0;
if(LINK_ID[0].Pid_Ack_Byte != (*rec)->type)
#include "gps.h"
-#include <time.h>
time_t GPS_Time_Now(void);
-int32 GPS_Packet_Read(int32 fd, GPS_PPacket *packet);
-int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet);
-int32 GPS_Get_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec);
-int32 ajb(int32 fd);
-
+int32 GPS_Serial_Packet_Read(gpsdevh *fd, GPS_PPacket *packet);
+int32 GPS_Serial_Get_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
#endif
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
#include "gps.h"
-static int32 GPS_A600_Rqst(int32 fd, time_t Time);
-static int32 GPS_A700_Rqst(int32 fd, double lat, double lon);
+static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time);
+static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon);
** @return [int32] true if OK
************************************************************************/
-int32 GPS_Rqst_Send_Time(int32 fd, time_t Time)
+int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time)
{
time_t ret=0;
**
** @return [int32] success
************************************************************************/
-static int32 GPS_A600_Rqst(int32 fd, time_t Time)
+static int32 GPS_A600_Rqst(gpsdevh *fd, time_t Time)
{
GPS_PPacket tra;
GPS_PPacket rec;
** @return [int32] success
************************************************************************/
-int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon)
+int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon)
{
int32 ret=0;
**
** @return [int32] success
************************************************************************/
-static int32 GPS_A700_Rqst(int32 fd, double lat, double lon)
+static int32 GPS_A700_Rqst(gpsdevh *fd, double lat, double lon)
{
GPS_PPacket tra;
GPS_PPacket rec;
#include "gps.h"
-int32 GPS_Rqst_Send_Time(int32 fd, time_t Time);
-int32 GPS_Rqst_Send_Position(int32 fd, double lat, double lon);
+int32 GPS_Rqst_Send_Time(gpsdevh *fd, time_t Time);
+int32 GPS_Rqst_Send_Position(gpsdevh *fd, double lat, double lon);
#endif
** @author Copyright (C) 1999 Alan Bleasby
** @version 1.0
** @modified Dec 28 1999 Alan Bleasby. First version
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
** Boston, MA 02111-1307, USA.
********************************************************************/
#include "gps.h"
-#include "gpsusbint.h"
+#include "gpsserial.h"
#include <stdio.h>
#include <errno.h>
** @return [void]
************************************************************************/
-void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
+void GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n)
{
UC *p;
UC *q;
p = data;
q = (*packet)->data;
- if (gps_is_usb) {
- GPS_Make_Packet_usb(packet, type, data, n);
- return;
- }
-
(*packet)->dle = DLE;
(*packet)->edle = DLE;
(*packet)->etx = ETX;
** @return [int32] number of bytes in the packet
************************************************************************/
-int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet)
+int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet)
{
size_t ret;
const char *m1, *m2;
-
- if (gps_is_usb)
- return GPS_Write_Packet_usb(fd, packet);
+
GPS_Diag("Tx Data:");
Diag(&packet->dle, 3);
** @return [int32] success
************************************************************************/
-int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec)
+int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec)
{
UC data[2];
- if (gps_is_usb)
- return 1;
-
GPS_Util_Put_Short(data,(US)(*rec)->type);
GPS_Make_Packet(tra,LINK_ID[0].Pid_Ack_Byte,data,2);
if(!GPS_Write_Packet(fd,*tra))
#define GPS_ARB_LEN 1024
-UC gps_sendbuf[GPS_ARB_LEN];
+void GPS_Serial_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n);
+int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
void GPS_Make_Packet(GPS_PPacket *packet, UC type, UC *data, int16 n);
-int32 GPS_Write_Packet(int32 fd, GPS_PPacket packet);
-int32 GPS_Send_Ack(int32 fd, GPS_PPacket *tra, GPS_PPacket *rec);
-
#endif
** @version 1.0
** @modified December 28th 1999 Alan Bleasby. First version
** @modified June 29th 2000 Alan Bleasby. NMEA additions
+** @modified Copyright (C) 2006 Robert Lipe
** @@
**
** This library is free software; you can redistribute it and/or
** Boston, MA 02111-1307, USA.
********************************************************************/
#include "gps.h"
-#include "garminusb.h"
+#include "gpsserial.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if defined (__WIN32__) || defined (__CYGWIN__)
#include <windows.h>
-/*
- * Rather than teaching the rest of this code about Windows serial APIs
- * we'll weenie out, violate good layering, and just keep our handle
- * internal. This means we ignore that 'fd' number that gets passed in.
- */
-
-static HANDLE comport;
+#include "gpsserial_win.h"
/*
* Display an error from the serial subsystem.
*/
-void GPS_Serial_Error(char *mb, ...)
+void GPS_Serial_Error(const char *mb, ...)
{
va_list ap;
char msg[200];
int b;
va_start(ap, mb);
-// strcpy(msg, msg);
b = vsnprintf(msg, sizeof(msg), mb, ap);
s = msg + b;
*s++ = ':';
GPS_Error(msg);
}
-int32 GPS_Serial_On(const char *port, int32 *fd)
+int32 GPS_Serial_On(const char *port, gpsdevh **dh)
{
DCB tio;
COMMTIMEOUTS timeout;
-
- if (gps_is_usb) {
- switch (gusb_open(port)) {
- case 0: return 0;
- case 1: return 1;
- case 2: exit(0);
- }
- }
+ HANDLE comport;
+ win_serial_data *wsd = xcalloc(sizeof (win_serial_data), 1);
+ *dh = (gpsdevh*) wsd;
comport = CreateFile(port, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
gps_errno = SERIAL_ERROR;
return 0;
}
- *fd = 1;
+ wsd->comport = comport;
return 1;
}
-int32 GPS_Serial_Off(const char *port, int32 fd)
+int32 GPS_Serial_Off(gpsdevh *dh)
{
- if (gps_is_usb) {
- gusb_close(port);
- } else {
- CloseHandle(comport);
- comport = INVALID_HANDLE_VALUE;
- }
+ win_serial_data *wsd = (win_serial_data*)dh;
+ CloseHandle(wsd->comport);
+ wsd->comport = INVALID_HANDLE_VALUE;
+ xfree(wsd);
return 1;
}
-int32 GPS_Serial_Chars_Ready(int32 fd)
+int32 GPS_Serial_Chars_Ready(gpsdevh *dh)
{
COMSTAT lpStat;
DWORD lpErrors;
+ win_serial_data *wsd = (win_serial_data*)dh;
- ClearCommError(comport, &lpErrors, &lpStat);
+ ClearCommError(wsd->comport, &lpErrors, &lpStat);
return (lpStat.cbInQue > 0);
}
-int32 GPS_Serial_Wait(int32 fd)
+int32 GPS_Serial_Wait(gpsdevh *fd)
{
-
- if (gps_is_usb) return 1;
-
/* Wait a short time before testing if data is ready.
* The GPS II, in particular, has a noticable time responding
* with a response to the device inquiry and if we give up on this
return GPS_Serial_Chars_Ready(fd);
}
-int32 GPS_Serial_Flush(int32 fd)
+int32 GPS_Serial_Flush(gpsdevh *fd)
{
return 1;
}
-int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size)
+int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size)
{
+ win_serial_data *wsd = (win_serial_data*)dh;
DWORD len;
/*
if (size == 0) {
return 0;
}
- WriteFile (comport, obuf, size, &len, NULL);
+ WriteFile (wsd->comport, obuf, size, &len, NULL);
if (len != (DWORD) size) {
fatal ("Write error. Wrote %d of %d bytes.\n", len, size);
}
return len;
}
-int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size)
+int32 GPS_Serial_Read(gpsdevh * dh, void *ibuf, int size)
{
DWORD cnt = 0;
+ win_serial_data *wsd = (win_serial_data*)dh;
- ReadFile(comport, ibuf, size, &cnt, NULL);
+ ReadFile(wsd->comport, ibuf, size, &cnt, NULL);
return cnt;
}
-int32 GPS_Serial_Close(int32 fd, const char *port)
-{
- return 1;
-}
-
#else
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
-
-static struct termios gps_ttysave;
+#include "gpsserial_posix.h"
/* @func GPS_Serial_Restoretty ***********************************************
**
** @return [int32] false upon error
************************************************************************/
-int32 GPS_Serial_Savetty(const char *port)
+static int32 GPS_Serial_Savetty(int32 fd)
{
- int32 fd;
-
- if (gps_is_usb) return 1;
-
- if((fd = open(port, O_RDWR))==-1)
- {
- perror("open");
- gps_errno = SERIAL_ERROR;
- GPS_Error("SERIAL: Cannot open serial port '%s'", port);
- return 0;
- }
-
if(tcgetattr(fd,&gps_ttysave)==-1)
{
- perror("tcgetattr");
gps_errno = HARDWARE_ERROR;
- GPS_Error("SERIAL: tcgetattr error");
- return 0;
- }
-
- if(!GPS_Serial_Close(fd,port))
- {
- gps_errno = SERIAL_ERROR;
- GPS_Error("GPS_Serial_Savetty: Close error");
+ GPS_Serial_Error("SERIAL: tcgetattr error");
return 0;
}
** @return [int32] false upon error
************************************************************************/
-int32 GPS_Serial_Restoretty(const char *port)
+static int32 GPS_Serial_Restoretty(int fd)
{
- int32 fd;
-
- if (gps_is_usb) return 1;
-
- if((fd = open(port, O_RDWR))==-1)
- {
- perror("open");
- gps_errno = HARDWARE_ERROR;
- GPS_Error("SERIAL: Cannot open serial port '%s'", port);
- return 0;
- }
-
if(tcsetattr(fd, TCSAFLUSH, &gps_ttysave)==-1)
{
- perror("ioctl");
gps_errno = HARDWARE_ERROR;
- GPS_Error("SERIAL: tcsetattr error");
+ GPS_Serial_Error("SERIAL: tcsetattr error");
return 0;
}
return 1;
}
-
+#endif
/* @func GPS_Serial_Open ***********************************************
**
** @return [int32] false upon error
************************************************************************/
-int32 GPS_Serial_Open(int32 *fd, const char *port)
+int32 GPS_Serial_Open(gpsdevh *dh, const char *port)
{
struct termios tty;
+ posix_serial_data *psd = (posix_serial_data *)dh;
/*
* This originally had O_NDELAY | O_NOCTTY in here, but this
* and the rest of the code doesn't _REALLY_ handle the partial
* write/retry case anyway. - robertl
*/
- if((*fd = open(port, O_RDWR))==-1)
+ if((psd->fd = open(port, O_RDWR))==-1)
{
- perror("open");
- GPS_Error("SERIAL: Cannot open serial port '%s'", port);
+ GPS_Serial_Error("XSERIAL: Cannot open serial port '%s'", port);
gps_errno = SERIAL_ERROR;
return 0;
}
- if(tcgetattr(*fd,&tty)==-1)
+ if(tcgetattr(psd->fd,&psd->gps_ttysave)==-1)
{
- perror("tcgetattr");
- GPS_Error("SERIAL: tcgetattr error");
- gps_errno = SERIAL_ERROR;
+ gps_errno = HARDWARE_ERROR;
+ GPS_Serial_Error("SERIAL: tcgetattr error");
return 0;
}
+ tty = psd->gps_ttysave;
tty.c_cflag &= ~(CSIZE);
tty.c_cflag |= (CREAD | CS8 | CLOCAL);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
- if(tcsetattr(*fd,TCSANOW,&tty)==-1)
+ if(tcsetattr(psd->fd,TCSANOW,&tty)==-1)
{
- perror("tcsetattr");
- GPS_Error("SERIAL: tcsetattr error");
+ GPS_Serial_Error("SERIAL: tcsetattr error");
return 0;
}
return 1;
}
-int32 GPS_Serial_Read(int32 handle, void *ibuf, int size)
+/*
+ * Display an error from the serial subsystem.
+ */
+void GPS_Serial_Error(const char *mb, ...)
+{
+ va_list ap;
+ char msg[200];
+ char *s;
+ int b;
+
+ va_start(ap, mb);
+ b = vsnprintf(msg, sizeof(msg), mb, ap);
+ s = msg + b;
+ *s++ = ':';
+ *s++ = ' ';
+
+// FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0,
+// GetLastError(), 0, s, sizeof(msg) - b - 2, 0 );
+ strcat(msg, strerror(errno));
+ GPS_Error(msg);
+}
+
+int32 GPS_Serial_Read(gpsdevh *dh, void *ibuf, int size)
{
+ posix_serial_data *psd = (posix_serial_data *)dh;
#if GARMULATOR
static int l;
static char *rp;
return 1;
#else
- return read(handle, ibuf, size);
+ return read(psd->fd, ibuf, size);
#endif
}
-int32 GPS_Serial_Write(int32 handle, const void *obuf, int size)
+int32 GPS_Serial_Write(gpsdevh *dh, const void *obuf, int size)
{
- return write(handle, obuf, size);
+ posix_serial_data *psd = (posix_serial_data *)dh;
+ return write(psd->fd, obuf, size);
}
**
** @return [int32] false upon error
************************************************************************/
-int32 GPS_Serial_Flush(int32 fd)
+int32 GPS_Serial_Flush(gpsdevh *fd)
{
- if (gps_is_usb) return 1;
-
- if(tcflush(fd,TCIOFLUSH))
+ posix_serial_data *psd = (posix_serial_data *)fd;
+
+ if(tcflush(psd->fd,TCIOFLUSH))
{
- perror("tcflush");
- GPS_Error("SERIAL: tcflush error");
+ GPS_Serial_Error("SERIAL: tcflush error");
gps_errno = SERIAL_ERROR;
return 0;
}
** @return [int32] false upon error
************************************************************************/
-int32 GPS_Serial_Close(int32 fd, const char *port)
+int32 GPS_Serial_Close(gpsdevh *fd)
{
- if (gps_is_usb) return 1;
+ posix_serial_data *psd = (posix_serial_data *)fd;
- if(close(fd)==-1)
+ if(tcsetattr(psd->fd, TCSAFLUSH, &psd->gps_ttysave)==-1)
{
- perror("close");
- GPS_Error("SERIAL: Error closing serial port");
+ gps_errno = HARDWARE_ERROR;
+ GPS_Serial_Error("SERIAL: tcsetattr error");
+ return 0;
+ }
+
+ if(close(psd->fd)==-1)
+ {
+ GPS_Serial_Error("SERIAL: Error closing serial port");
gps_errno = SERIAL_ERROR;
return 0;
}
** @return [int32] true if chars waiting
************************************************************************/
-int32 GPS_Serial_Chars_Ready(int32 fd)
+int32 GPS_Serial_Chars_Ready(gpsdevh *dh)
{
fd_set rec;
struct timeval t;
+ posix_serial_data *psd = (posix_serial_data *)dh;
+ int32 fd = psd->fd;
+
#if GARMULATOR
static foo;
/* Return sporadic reads just to torment the rest of the code. */
** @return [int32] true if serial chars waiting
************************************************************************/
-int32 GPS_Serial_Wait(int32 fd)
+int32 GPS_Serial_Wait(gpsdevh *dh)
{
fd_set rec;
struct timeval t;
-
- if (gps_is_usb) return 1;
+ posix_serial_data *psd = (posix_serial_data *)dh;
FD_ZERO(&rec);
- FD_SET(fd,&rec);
+ FD_SET(psd->fd,&rec);
t.tv_sec = 0;
- t.tv_usec = usecDELAY;
+ t.tv_usec = 180000; /* Microseconds before GPS sends A001 */
- (void) select(fd+1,&rec,NULL,NULL,&t);
- if(FD_ISSET(fd,&rec))
+ (void) select(psd->fd+1,&rec,NULL,NULL,&t);
+ if(FD_ISSET(psd->fd,&rec))
return 1;
return 0;
** @return [int32] success
************************************************************************/
-int32 GPS_Serial_On(const char *port, int32 *fd)
+int32 GPS_Serial_On(const char *port, gpsdevh **dh)
{
- if (gps_is_usb) {
- return gusb_init(port);
- }
- if(!GPS_Serial_Savetty(port))
- {
- GPS_Error("Cannot access serial port '%s'", port);
- gps_errno = SERIAL_ERROR;
- return 0;
- }
+ posix_serial_data *psd = xcalloc(sizeof (posix_serial_data), 1);
+ *dh = (gpsdevh*) psd;
- if(!GPS_Serial_Open(fd,port))
+ if(!GPS_Serial_Open((gpsdevh *) psd,port))
{
GPS_Error("Cannot open serial port '%s'", port);
gps_errno = SERIAL_ERROR;
** @return [int32] success
************************************************************************/
-int32 GPS_Serial_Off(const char *port, int32 fd)
+int32 GPS_Serial_Off(gpsdevh *dh)
{
- if(!GPS_Serial_Close(fd,port))
+
+ if(!GPS_Serial_Close(dh))
{
GPS_Error("Error Closing port");
gps_errno = HARDWARE_ERROR;
return 0;
}
+ dh = NULL;
- if(!GPS_Serial_Restoretty(port))
- {
- GPS_Error("Error restoring port");
- gps_errno = HARDWARE_ERROR;
- return 0;
- }
-
return 1;
}
#define usecDELAY 180000 /* Microseconds before GPS sends A001 */
-int32 GPS_Serial_Chars_Ready(int32 fd);
-int32 GPS_Serial_Close(int32 fd, const char *port);
-int32 GPS_Serial_Open(int32 *fd, const char *port);
-int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port);
-int32 GPS_Serial_Restoretty(const char *port);
-int32 GPS_Serial_Savetty(const char *port);
-int32 GPS_Serial_On(const char *port, int32 *fd);
-int32 GPS_Serial_Off(const char *port, int32 fd);
-int32 GPS_Serial_Wait(int32 fd);
-int32 GPS_Serial_Flush(int32 fd);
-int32 GPS_Serial_On_NMEA(const char *port, int32 *fd);
-int32 GPS_Serial_Read(int32 ignored, void *ibuf, int size);
-int32 GPS_Serial_Write(int32 ignored, const void *obuf, int size);
-void GPS_Serial_Error(char *hdr, ...);
+int32 GPS_Serial_Chars_Ready(gpsdevh * fd);
+// int32 GPS_Serial_Close(int32 fd, const char *port);
+// int32 GPS_Serial_Open(int32 *fd, const char *port);
+// int32 GPS_Serial_Open_NMEA(int32 *fd, const char *port);
+// int32 GPS_Serial_Restoretty(const char *port);
+// int32 GPS_Serial_Savetty(const char *port);
+int32 GPS_Serial_On(const char *port, gpsdevh **fd);
+int32 GPS_Serial_Off(gpsdevh *fd);
+int32 GPS_Serial_Wait(gpsdevh *fd);
+int32 GPS_Serial_Flush(gpsdevh *fd);
+// int32 GPS_Serial_On_NMEA(const char *port, gpsdevh **fd);
+int32 GPS_Serial_Read(gpsdevh *fd, void *ibuf, int size);
+int32 GPS_Serial_Write(gpsdevh *fd, const void *obuf, int size);
+int32 GPS_Serial_Write_Packet(gpsdevh *fd, GPS_PPacket packet);
+int32 GPS_Serial_Send_Ack(gpsdevh *fd, GPS_PPacket *tra, GPS_PPacket *rec);
+void GPS_Serial_Error(const char *hdr, ...);
#endif
*/
-#include <usb.h>
#include "gps.h"
#include "garminusb.h"
-
+#include "gpsusbcommon.h"
/*
* This receive logic is a little convoluted as we go to some efforts here
rs_frombulk
} receive_state;
+static gusb_llops_t *gusb_llops;
+
+/* Decide when to truncate packets for debug output */
+#define DEBUG_THRESH ((global_opts.debug_level < 5) && (i > 10))
+
+/* Called from OS layer to register its low-level entry points. */
+void
+gusb_register_ll(gusb_llops_t *p)
+{
+ gusb_llops = p;
+}
+
int
-gusb_close(const char *portname)
+gusb_close(gpsdevh *dh)
{
garmin_usb_packet scratch;
+
+ memset(&scratch, 0, sizeof(scratch));
+
switch (receive_state) {
case rs_frombulk:
gusb_cmd_get(&scratch, sizeof(scratch));
break;
+ default:
+ break;
+ }
+
+ gusb_llops->llop_close(dh);
+ return 1;
+
+#if BOOGER
+ garmin_usb_packet scratch = {0};
+abort();
+ switch (receive_state) {
+ case rs_frombulk:
+ gusb_cmd_get(dh, &scratch, sizeof(scratch));
+ break;
}
return 1;
+#endif
}
{
int rv;
unsigned char *buf = (unsigned char *) &ibuf->dbuf;
-
+ int orig_receive_state;
top:
+ orig_receive_state = receive_state;
switch (receive_state) {
case rs_fromintr:
- rv = gusb_cmd_get_os(ibuf, sz);
- break;
+ rv = gusb_llops->llop_get_intr(ibuf, sz);
+ break;
case rs_frombulk:
- rv = gusb_cmd_get_os_bulk(ibuf, sz);
- if (rv == 0) {
- receive_state = rs_fromintr;
- }
- break;
+ rv = gusb_llops->llop_get_bulk(ibuf, sz);
+ break;
+ default:
+ fatal("Unknown receiver state %d\n", receive_state);
}
if (gps_show_bytes) {
GPS_Diag("RX (%s) [%d]:",
receive_state == rs_fromintr ? "intr" : "bulk", rv);
- for(i=0;i<rv;i++)
+ for(i=0;i<rv;i++) {
+ if (DEBUG_THRESH) {
+ GPS_Diag("[...]");
+ break;
+ }
GPS_Diag("%02x ", buf[i]);
+ }
- for(i=0;i<rv;i++)
+ for(i=0;i<rv;i++) {
+ if (DEBUG_THRESH) {
+ GPS_Diag("[...]");
+ break;
+ }
GPS_Diag("%c", isalnum(buf[i])? buf[i] : '.');
+ }
m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0],
ibuf->gusb_pkt.databuf[0], &m2);
+if ((rv == 0) && (receive_state == rs_frombulk) ) {m1= "RET2INTR";m2=NULL;};
GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
}
- if (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK) {
+ /* Adjust internal state and retry the read */
+ if ((rv > 0) && (ibuf->gusb_pkt.pkt_id[0] == GUSB_REQUEST_BULK)) {
receive_state = rs_frombulk;
goto top;
}
+ /*
+ * If we were reading from the bulk pipe and we just got
+ * a zero request, adjust our internal state.
+ * It's tempting to retry the read here to hide this "stray"
+ * packet from our callers, but that only works when you know
+ * there's another packet coming. That works in every case
+ * except the A000 discovery sequence.
+ */
+ if ((receive_state == rs_frombulk) && (rv <= 0)) {
+ receive_state = rs_fromintr;
+ }
return rv;
}
int
gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
{
- int rv, i;
+ unsigned int rv, i;
unsigned char *obuf = (unsigned char *) &opkt->dbuf;
const char *m1, *m2;
- rv = gusb_cmd_send_os(opkt, sz);
+ rv = gusb_llops->llop_send(opkt, sz);
if (gps_show_bytes) {
GPS_Diag("TX [%d]:", sz);
for (i = 0; i < GUSB_MAX_UNITS; i++) {
if (garmin_unit_info[i].serial_number) {
- printf("%d %u %s\n", i,
+ printf("%d %lu %lu %s\n", i,
garmin_unit_info[i].serial_number,
+ garmin_unit_info[i].unit_id,
garmin_unit_info[i].product_identifier
);
}
}
}
-char *
-gusb_id_unit(void)
+void
+gusb_id_unit(struct garmin_unit_info *gu)
{
static const char oid[12] =
{20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
garmin_usb_packet iresp;
int i;
- char *rv = NULL;
gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid));
for (i = 0; i < 25; i++) {
iresp.gusb_pkt.type = 0;
if (gusb_cmd_get(&iresp, sizeof(iresp)) < 0) {
- return rv;
+ return;
}
if (le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
- rv = strdup((char *) iresp.gusb_pkt.databuf+4);
+ gu->product_identifier = xstrdup((char *) iresp.gusb_pkt.databuf+4);
+ gu->unit_id = le_read16(iresp.gusb_pkt.databuf+0);
+ gu->unit_version = le_read16(iresp.gusb_pkt.databuf+2);
}
+ /*
+ * My goodnesss, this is fragile. During command syncup,
+ * we need to know if we're at the end. The 0xfd packet
+ * is promised by Garmin engineering to be the last.
+ */
+ if (le_read16(iresp.gusb_pkt.pkt_id) == 0xfd) return;
}
-fatal("eek!");
-
+ fatal("Unable to sync with Garmin USB device in %d attempts.", i);
}
void
garmin_usb_packet iresp;
int i;
+ /*
+ * This is our first communication with the unit.
+ */
+ receive_state = rs_fromintr;
+
for(i = 0; i < 25; i++) {
le_write16(&iresp.gusb_pkt.pkt_id, 0);
le_write32(&iresp.gusb_pkt.datasz, 0);
(le_read32(iresp.gusb_pkt.datasz) == 4)) {
unsigned serial_number = le_read32(iresp.gusb_pkt.databuf);
garmin_unit_info[unit_number].serial_number = serial_number;
- garmin_unit_info[unit_number].product_identifier = gusb_id_unit();
+ gusb_id_unit(&garmin_unit_info[unit_number]);
unit_number++;
These symbols should not be publicly used. They're "friend" functions
of USB details internal to jeeps.
- Copyright (C) 2005 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2005, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet);
+int32 GPS_Packet_Read_usb(gpsdevh *fd, GPS_PPacket *packet, int eatbulk);
void GPS_Make_Packet_usb(GPS_PPacket *packet, UC type, UC *data, int16 n);
-int32 GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet);
+int32 GPS_Write_Packet_usb(gpsdevh *fd, GPS_PPacket packet);
/*
Decompose an incoming USB packet to make it look like a serial one.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "garminusb.h"
#include "gpsusbint.h"
-int32 GPS_Packet_Read_usb(int32 fd, GPS_PPacket *packet)
+/*
+ * Return values are:
+ * Negative on error.
+ * 1 if read success - even if empty packet.
+ */
+int32 GPS_Packet_Read_usb(gpsdevh *dh, GPS_PPacket *packet, int eat_bulk)
{
int32 n;
- int32 i;
int32 payload_size;
- const char *m1;
- const char *m2;
garmin_usb_packet pkt;
+
memset(&pkt, 0, sizeof(pkt));
+do_over:
n = gusb_cmd_get(&pkt, sizeof(pkt));
- if ( n <= 0 ) {
-// FIXME: revisit why we're intermittend getting read errors here...
-// fprintf(stderr, "Eeek %d\n", n);
- (*packet)->n = (UC) 0;
+ if ( n < 0 ) {
+fprintf(stderr, "Eeek %d\n", n);
return n;
}
- if (1 && gps_show_bytes) {
- GPS_Diag("\nRx Data:[%d]",n);
- for (i = 0; i < n; i++)
- GPS_Diag("%02x ", pkt.dbuf[i]);
- for (i = 0; i < n; i++)
- GPS_Diag("%c", isalnum(pkt.dbuf[i]) ? pkt.dbuf[i] : '.');
- m1 = Get_Pkt_Type(pkt.gusb_pkt.pkt_id[0], pkt.gusb_pkt.databuf[0], &m2);
- GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
-
+ /*
+ * This is a horrible hack for 276/296. This family sometimes
+ * switches between bulk and interrupt on EVERY packet. Rather
+ * than bother all the callers with that bit of unpleasantness,
+ * silently consume zero byte "switch back to intr" packets here.
+ *
+ * The one caller that doesn't want this hidden is device discovery
+ * in the A000 handler.
+ */
+ if ((n == 0) && eat_bulk) {
+ goto do_over;
}
-
+
/*
* Populate members of serial packet from USB packet. The
* copy here seems wasteful, but teaching all the callers about
payload_size = le_read32(&pkt.gusb_pkt.datasz);
(*packet)->n = (UC) payload_size;
memcpy((*packet)->data, &pkt.gusb_pkt.databuf, payload_size);
- return payload_size;
+
+ return 1;
}
/*
Form GarminUSB packets to send.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2005, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
int32
-GPS_Write_Packet_usb(int32 fd, GPS_PPacket packet)
+GPS_Write_Packet_usb(gpsdevh *dh, GPS_PPacket packet)
{
garmin_usb_packet gp;
memset(&gp, 0, sizeof(gp));
/*
Stubs to keep build happy when USB just isn't available to us.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-#include "garminusb.h"
#include "config.h"
-#if !HAVE_LIBUSB
+#if !HAVE_LIBUSB
+#include "garminusb.h"
const char no_usb[] = "USB suport is not available in this build.\n";
int
/*
Windows layer of Garmin/USB protocol.
- Copyright (C) 2004 Robert Lipe, robertlipe@usa.net
+ Copyright (C) 2004, 2006, 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "gps.h"
#include "gpsapp.h"
#include "garminusb.h"
+#include "gpsusbcommon.h"
+#include "gpsusbwin.h"
/* Constants from Garmin doc. */
(FILE_DEVICE_UNKNOWN, 0x851, METHOD_BUFFERED, FILE_ANY_ACCESS)
-static HANDLE *usb_handle ;
+static HANDLE *usb_handle = INVALID_HANDLE_VALUE;
static int usb_tx_packet_size ;
-static const char oinit[12] = {0, 0, 0, 0, 0x05, 0, 0, 0, 0, 0, 0, 0};
-garmin_usb_packet iresp;
-garmin_usb_packet iresp_junk;
-static int ct;
-
-static char * id_unit(void);
-
-int
-gusb_open(const char *pname)
-{
- int maxtries;
- int maxct = 10;
- int unit_number = 0;
- int req_unit_number = 0;
-
- SP_INTERFACE_DEVICE_DATA devinterface;
- PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
- SP_DEVINFO_DATA devinfo;
- HDEVINFO hdevinfo;
- DWORD size;
- if (ct++) return 1;
-
- if (strlen(pname) > 4) {
- req_unit_number = atoi(pname+4);
- GPS_Diag("Searching for USB unit number %d\n", unit_number);
-// if (req_unit_number == -2) {
-// printf("%d %u %s\n", 0, 3019840053, "GPSMap60CS Software Version 3.50");
-// exit(0);
-// }
- }
-
- hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL,
- DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
-
- if (hdevinfo == INVALID_HANDLE_VALUE) {
- GPS_Serial_Error("SetupDiGetClassDevs failed");
- warning("Is the Garmin USB driver installed?");
- return 0;
- }
-
- /* Get the device associated with this index. */
- devinterface.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
- if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL, (GUID *) &GARMIN_GUID,
- 0, &devinterface)) {
- GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
- warning("Is the Garmin USB unit powered up and connected?");
- return 0;
- }
-
- SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface,
- NULL, 0, &size, NULL);
-
- pdd = malloc(size);
- pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
- devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
-
- if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, &devinterface, pdd, size, NULL, &devinfo)) {
- GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail");
- return 0;
- }
-
- /* Whew. All that just to get something we can open... */
- GPS_Diag("Windows GUID for interface %d is \n\t%s\n", unit_number,
- pdd->DevicePath);
- usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING, 0, NULL );
- if (usb_handle == INVALID_HANDLE_VALUE) {
- GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath);
- return 0;
- }
-
- if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE, NULL, 0,
- &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE, &size, NULL)) {
- fatal("Couldn't get USB packet size.\n");
- }
-
- if (pdd) {
- free(pdd);
- }
- SetupDiDestroyDeviceInfoList(hdevinfo);
-
- for (maxtries = maxct; maxtries; maxtries--) {
-
- le_write16(&iresp.gusb_pkt.pkt_id, 0);
- le_write32(&iresp.gusb_pkt.datasz, 0);
- le_write32(&iresp.gusb_pkt.databuf, 0);
-
- gusb_cmd_send((const garmin_usb_packet *) oinit, sizeof(oinit));
- gusb_cmd_get(&iresp, sizeof(iresp));
-
- if ((le_read16(iresp.gusb_pkt.pkt_id) == 6) &&
- (le_read32(iresp.gusb_pkt.datasz) == 4)) {
- unsigned serial_number = le_read32(iresp.gusb_pkt.databuf);
- GPS_Diag("Serial %u. Synced in %d\n",
- serial_number,
- maxct - maxtries);
- garmin_unit_info[unit_number].serial_number = serial_number;
- garmin_unit_info[unit_number].os_identifier = strdup(pdd->DevicePath);
- garmin_unit_info[unit_number].product_identifier = id_unit();
- if (req_unit_number < 0) {
- printf("%d %u %s\n", unit_number, serial_number, garmin_unit_info[unit_number].product_identifier);
- return 2;
- }
- return 1;
- }
- }
- fatal("Unable to establish USB syncup within %d tries.\n", maxct);
- return 0;
-}
-
int
-gusb_close(const char *portname)
+gusb_win_close(const char *portname)
{
if (usb_handle != INVALID_HANDLE_VALUE) {
-#if 0
- /* FIXME: we should probably release things and delete the "ct"
- * reference count above...
- */
CloseHandle(usb_handle);
usb_handle = INVALID_HANDLE_VALUE;
-#endif
}
- return 0;
+
+ return 0;
}
-int
-gusb_cmd_get(garmin_usb_packet *ibuf, size_t sz)
+static int
+gusb_win_get(garmin_usb_packet *ibuf, size_t sz)
{
DWORD rxed = GARMIN_USB_INTERRUPT_DATA_SIZE;
unsigned char *buf = (unsigned char *) &ibuf->dbuf;
- int i;
int tsz=0;
unsigned char *obuf = buf;
break;
}
}
-
- if (gps_show_bytes) {
- const char *m1, *m2;
- printf("RX [%d]:", tsz);
- for(i=0;i<tsz;i++)
- GPS_Diag("%02x ", obuf[i]);
- for(i=0;i<tsz;i++)
- GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
-
- m1 = Get_Pkt_Type(ibuf->gusb_pkt.pkt_id[0], ibuf->gusb_pkt.databuf[0], &m2);
- GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
- printf("\n");
- }
return tsz;
}
-int
-gusb_cmd_send(const garmin_usb_packet *opkt, size_t sz)
+static int
+gusb_win_get_bulk(garmin_usb_packet *ibuf, size_t sz)
+{
+ int n;
+ DWORD rsz;
+ unsigned char *buf = (unsigned char *) &ibuf->dbuf;
+
+ n = ReadFile(usb_handle, buf, sz, &rsz, NULL);
+
+ return rsz;
+}
+
+static int
+gusb_win_send(const garmin_usb_packet *opkt, size_t sz)
{
DWORD rsz;
- size_t i;
unsigned char *obuf = (unsigned char *) &opkt->dbuf;
- const char *m1, *m2;
/* The spec warns us about making writes an exact multiple
* of the packet size, but isn't clear whether we can issue
* data in a single call to WriteFile if it spans buffers.
*/
WriteFile(usb_handle, obuf, sz, &rsz, NULL);
- if (gps_show_bytes) {
- printf("TX [%d]:", rsz);
- for(i=0;i<rsz;i++)
- GPS_Diag("%02x ", obuf[i]);
- for(i=0;i<rsz;i++)
- GPS_Diag("%c", isalnum(obuf[i])? obuf[i] : '.');
- m1 = Get_Pkt_Type(opkt->gusb_pkt.pkt_id[0], opkt->gusb_pkt.databuf[0], &m2);
- GPS_Diag("(%-8s%s)\n", m1, m2 ? m2 : "");
- }
if (rsz != sz) {
fatal ("Error sending %d bytes. Successfully sent %d\n", sz, rsz);
return rsz;
}
-static char *
-id_unit(void)
+static gusb_llops_t win_llops = {
+ gusb_win_get,
+ gusb_win_get_bulk,
+ gusb_win_send,
+ gusb_win_close
+};
+
+static
+HANDLE * garmin_usb_start(HDEVINFO* hdevinfo, SP_DEVICE_INTERFACE_DATA *infodata)
{
-static const unsigned char oid[12] = {20, 0, 0, 0, 0xfe, 0, 0, 0, 0, 0, 0, 0};
- /*
- * Identify the unit before getting into all the protocol gunk.
- * We get two packets back, but we discard the protocol array
- * for now.
- */
+ DWORD size;
+ PSP_INTERFACE_DEVICE_DETAIL_DATA pdd = NULL;
+ SP_DEVINFO_DATA devinfo;
+
+ SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata,
+ NULL, 0, &size, NULL);
+
+ pdd = xmalloc(size);
+ pdd->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
+
+ devinfo.cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!SetupDiGetDeviceInterfaceDetail(hdevinfo, infodata,
+ pdd, size, NULL, &devinfo)) {
+ GPS_Serial_Error("SetupDiGetDeviceInterfaceDetail");
+ return NULL;
+ }
- gusb_cmd_send((garmin_usb_packet *)oid, sizeof(oid));
- gusb_cmd_get(&iresp, sizeof(iresp));
- gusb_cmd_get(&iresp_junk, sizeof(iresp_junk));
+ /* Whew. All that just to get something we can open... */
+ GPS_Diag("Windows GUID for interface is \n\t%s\n",
+ pdd->DevicePath);
- if (iresp.gusb_pkt.type == 20 &&
- le_read16(iresp.gusb_pkt.pkt_id) == 0xff) {
- return strdup(iresp.gusb_pkt.databuf+4);
+ if (usb_handle != INVALID_HANDLE_VALUE) {
+ fatal("garmin_usb_start called while device already started.\n");
}
- return NULL;
-}
+ usb_handle = CreateFile(pdd->DevicePath, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL );
+ if (usb_handle == INVALID_HANDLE_VALUE) {
+ GPS_Serial_Error("CreateFile on '%' failed", pdd->DevicePath);
+ return NULL;
+ }
+
+ if(!DeviceIoControl(usb_handle, IOCTL_GARMIN_USB_BULK_OUT_PACKET_SIZE,
+ NULL, 0, &usb_tx_packet_size, GARMIN_USB_INTERRUPT_DATA_SIZE,
+ &size, NULL)) {
+ fatal("Couldn't get USB packet size.\n");
+ }
+
+ gusb_syncup();
+ return usb_handle;
+}
-#if 0
-main()
+/*
+ * Main entry point from the upper layer. Walk the device tree, find our
+ * device, and light it up.
+ */
+int
+gusb_init(const char *pname, gpsdevh **dh)
{
- DWORD sz;
-char ocmd[] = {00, 00, 00, 00, 05, 00, 00, 00, 00, 00, 00, 00};
-char ocmd2[] = {0x14, 00, 00, 00, 0xfe, 00, 00, 00, 00, 00, 00, 00};
- gusb_open();
- WriteFile(usb_handle, ocmd, sizeof(ocmd), &sz, NULL);
- printf("Wrote %d\n", sz);
- usb_intr_get();
-
- WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL);
- printf("Wrote %d\n", sz);
- usb_intr_get();
-
- WriteFile(usb_handle, ocmd2, sizeof(ocmd2), &sz, NULL);
- printf("Wrote %d\n", sz);
- usb_intr_get();
+ int req_unit_number = 0;
+ int un = 0;
+ int match;
+
+ HDEVINFO hdevinfo;
+ SP_DEVICE_INTERFACE_DATA devinterface;
+
+ winusb_unit_data *wud = xcalloc(sizeof (winusb_unit_data), 1);
+ *dh = (gpsdevh*) wud;
+
+ gusb_register_ll(&win_llops);
+
+ if (strlen(pname) > 4) {
+ req_unit_number = atoi(pname+4);
+ }
+
+ hdevinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_GUID, NULL, NULL,
+ DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+
+ if (hdevinfo == INVALID_HANDLE_VALUE) {
+ GPS_Serial_Error("SetupDiGetClassDevs failed");
+ warning("Is the Garmin USB driver installed?");
+ return 0;
+ }
+
+ devinterface.cbSize = sizeof(devinterface);
+
+ if (req_unit_number >= 0) {
+ if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL,
+ (GUID *) &GARMIN_GUID,
+ req_unit_number, &devinterface)) {
+ GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
+ warning("Is the Garmin USB unit number %d powered up and connected?", un);
+ return 0;
+ }
+ /* We've matched. Now start the specific unit. */
+ garmin_usb_start(hdevinfo, &devinterface);
+ return 1;
+ }
+
+ /*
+ * Out unit nunber is less than zero, so loop over all units
+ * and display them.
+ */
+ for(match = 0;;match++) {
+ if (!SetupDiEnumDeviceInterfaces(hdevinfo, NULL,
+ (GUID *) &GARMIN_GUID, match, &devinterface)) {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+ break;
+ } else {
+ GPS_Serial_Error("SetupDiEnumDeviceInterfaces");
+ warning("Is the Garmin USB unit number %d powered up and connected?", un);
+ return 0;
+ }
+ }
+ /* We've matched. Now start the specific unit. */
+ garmin_usb_start(hdevinfo, &devinterface);
+ gusb_close("blah");
+ }
+ gusb_list_units();
+ exit (0);
}
-#endif
+
#endif /* !defined(NO_USB) */
void GPS_Warning(char *s);
void GPS_Error(char *fmt, ...);
+void GPS_Serial_Error(const char *hdr, ...);
void GPS_Fatal(char *s);
void GPS_Enable_Error(void);
void GPS_Enable_Warning(void);